package com.csii.activiti.server.core.listener;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.csii.activiti.server.abstraction.constant.MessageType;
import com.csii.activiti.server.abstraction.entity.ActFlowRemoteCallback;
import com.csii.activiti.server.abstraction.entity.ActReceivedBy;
import com.csii.activiti.server.abstraction.entity.ActSendMessage;
import com.csii.activiti.server.abstraction.service.ActMessageService;
import com.csii.activiti.server.core.constant.ActFlowActionSettingConstant;
import com.csii.activiti.server.core.constant.ActFlowDataManageConstant;
import com.csii.activiti.server.core.constant.ApprovalConfigConstant;
import com.csii.activiti.server.core.constant.CommonConstant;
import com.csii.activiti.server.core.engine.EngineService;
import com.csii.activiti.server.core.entity.ActFlowCache;
import com.csii.activiti.server.core.entity.db.ActFlowPublishConfigEntity;
import com.csii.activiti.server.core.listener.base.BaseSimpleTaskListener;
import com.csii.activiti.server.core.listener.enums.TaskOperateEnum;
import com.csii.activiti.server.core.mapper.ActFlowPublishConfigurationMapper;
import com.csii.activiti.server.core.service.FlowCallbackManagementService;
import com.csii.activiti.server.core.service.FlowDataManagementService;
import com.csii.activiti.server.core.utils.ELUtils;
import com.github.benmanes.caffeine.cache.Cache;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.delegate.event.ActivitiEvent;
import org.activiti.engine.delegate.event.ActivitiEventListener;
import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.delegate.event.impl.ActivitiEntityEventImpl;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntityImpl;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Component
@Slf4j
public class AutoApprovalListener implements ActivitiEventListener, Serializable {
    private static final long serialVersionUID = 1L;

    @Autowired
    private TaskService taskService;

    @Autowired
    private ActMessageService actMessageService;

    @Autowired
    private RuntimeService runtimeService;

    @Resource(name = "caffeineCache")
    private Cache<String,Object> cache;

    @Autowired
    private FlowDataManagementService flowDataManagementService;

    @Autowired
    private FlowCallbackManagementService flowCallbackManagementService;

    @Autowired
    private ActFlowPublishConfigurationMapper actFlowPublishConfigurationMapper;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private EngineService engineService;

    @Autowired(required = false)
    private List<BaseSimpleTaskListener> baseSimpleTaskListenerList;

    @Override
    public void onEvent(ActivitiEvent event) {
        if (ActivitiEventType.TASK_CREATED.equals(event.getType()) && event instanceof ActivitiEntityEventImpl){
            TaskEntityImpl task = (TaskEntityImpl) ((ActivitiEntityEventImpl) event).getEntity();
            ExecutionEntity processInstance = task.getProcessInstance();
            if (ApprovalConfigConstant.AUTO_BYPASS.equals(task.getAssignee())) {
                complete(task,"审批人为空,系统自动审批");
                return;
            }else if (ApprovalConfigConstant.AUTO_REJECTED.equals(task.getAssignee())){
                backTask(task,"审批人为空,系统自动审批",processInstance);
                return;
            }

            //规则处理
            ActFlowCache actFlowCache = (ActFlowCache) cache.getIfPresent(task.getProcessInstanceId() + task.getTaskDefinitionKey());
            if (actFlowCache != null) {
                //发起人相同过滤
                if (actFlowCache.isOriginatorSameFilter()){
                    String initiator = processInstance.getStartUserId();
                    if (task.getAssignee().equals(initiator)){
                        complete(task,"发起人相同过滤,系统自动审批");
                        return;
                    }
                }
                //相邻节点合并
                if (actFlowCache.isMergeAdjacentNodes()){
                    if (CollUtil.isNotEmpty(actFlowCache.getLastUsers()) && actFlowCache.getLastUsers().contains(task.getAssignee())){
                        complete(task,"相邻节点合并,系统自动审批");
                        return;
                    }
                }

            }
        }
    }

    private void complete(Task task, String command){
        taskService.addComment(task.getId(),task.getProcessInstanceId(),command);
        try {
            engineService.complete(task.getId());
            //监听通知
            if (baseSimpleTaskListenerList != null){
                for (BaseSimpleTaskListener baseSimpleTaskListener : baseSimpleTaskListenerList) {
                    baseSimpleTaskListener.notify(task, TaskOperateEnum.AGREE);
                }
            }
        }catch (Exception e){
            //异常情况回滚
            log.error("task auto complete is error task:{} e:{}",task,e);
            taskService.deleteComments(task.getId(),task.getProcessInstanceId());
        }
    }

    private void backTask(Task task,String command,ExecutionEntity processInstance){
        taskService.addComment(task.getId(),task.getProcessInstanceId(),command);
        //获取表单数据
        Map<String,Object> formData = (Map<String, Object>) processInstance.getVariable(CommonConstant.FORM_DATA);
        List<ActFlowRemoteCallback> callbackVariableInstance = (List<ActFlowRemoteCallback>) processInstance.getVariable(CommonConstant.REMOTE_URL);
        try {
            engineService.deleteProcessInstance(task.getProcessInstanceId(), ActFlowActionSettingConstant.REJECT);
        }catch (Exception e){
            //异常情况回滚
            log.error("task auto backTask is error task:{} e:{}",task,e);
            taskService.deleteComments(task.getId(),task.getProcessInstanceId());
            return;
        }
        //写入数据库
        flowDataManagementService.addData(formData,processInstance, ActFlowDataManageConstant.REJECTED.getStatus());
        //send message
        ActSendMessage sendMessage = new ActSendMessage();
        sendMessage.setTenantId(processInstance.getTenantId());
        sendMessage.setProcessName(processInstance.getProcessDefinitionName());
        sendMessage.setProcessDefinitionId(task.getProcessDefinitionId());
        sendMessage.setProcessKey(processInstance.getProcessDefinitionKey());
        sendMessage.setProcessInstanceId(task.getProcessInstanceId());
        sendMessage.setInitiator(processInstance.getStartUserId());
        sendMessage.setFormData(formData);
        sendMessage.setReceivedByList(CollUtil.newArrayList(new ActReceivedBy(null,processInstance.getStartUserId())));
        sendMessage.setCurrentNodeId(task.getTaskDefinitionKey());
        sendMessage.setCurrentNodeName(task.getName());
        sendMessage.setCurrentApprove(task.getAssignee());
        sendMessage.setApproveOpinion(command);
        if (callbackVariableInstance != null){
            sendMessage.setCallbackList(callbackVariableInstance);
        }
        sendMessage.setCurrentDate(new Date());
        String deploymentId = repositoryService.createProcessDefinitionQuery().processDefinitionId(sendMessage.getProcessDefinitionId()).singleResult().getDeploymentId();
        ActFlowPublishConfigEntity flowPublish = actFlowPublishConfigurationMapper.selectOne(new LambdaQueryWrapper<ActFlowPublishConfigEntity>().select(ActFlowPublishConfigEntity::getId, ActFlowPublishConfigEntity::getIconType,ActFlowPublishConfigEntity::getSummary,ActFlowPublishConfigEntity::getManyConditionJson).eq(ActFlowPublishConfigEntity::getId, deploymentId));
        if (flowPublish != null){
            sendMessage.setIconType(flowPublish.getIconType());
            sendMessage.setSummary(ELUtils.getSummary(flowPublish.getSummary(),flowPublish.getManyConditionJson(),formData));
        }

        actMessageService.sendMessage(sendMessage, MessageType.reject);

        //触发回调
        flowCallbackManagementService.callback(sendMessage,MessageType.reject.getType());

        //监听通知
        if (baseSimpleTaskListenerList != null){
            for (BaseSimpleTaskListener baseSimpleTaskListener : baseSimpleTaskListenerList) {
                baseSimpleTaskListener.notify(task, TaskOperateEnum.REJECT);
            }
        }
    }

    @Override
    public boolean isFailOnException() {
        return false;
    }
}
